package com.dbflow5.provider;

import com.dbflow5.DBFlowInstrumentedTestRule;
import com.dbflow5.DemoApp;
import com.dbflow5.config.DatabaseConfig;
import com.dbflow5.config.FlowConfig;
import com.dbflow5.config.FlowManager;
import com.dbflow5.database.OhosSQLiteOpenHelper;
import com.dbflow5.query.SQLite;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.util.ArrayList;

import static com.dbflow5.query.SQLite.delete;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * 该单元测试类由于无法注册DataAbility组件，导致无法进行单元测试
 */
public class ContentProviderTests {
    @Rule
    public DBFlowInstrumentedTestRule dblflowTestRule;
    private final DataAbilityHelper mockContentResolver;

    public ContentProviderTests() {
        this.dblflowTestRule = DBFlowInstrumentedTestRule.create(builder -> {
            DatabaseConfig.Builder builder1 = DatabaseConfig.builder(ContentProviderObjects.ContentDatabase.class, OhosSQLiteOpenHelper.createHelperCreator(AbilityDelegatorRegistry.getAbilityDelegator().getAppContext()));
            builder1.databaseName("content");
            FlowConfig.builder(DemoApp.context)
                .database(builder1.build()).build();
            return null;
        });
        this.mockContentResolver = DataAbilityHelper.creator(DemoApp.context);
    }

    @Before
    public void overrideContentResolver() {
        FlowManager.globalContentResolver = mockContentResolver;
    }

    @Test
    public void testContentProviderUtils() {
        FlowManager.database(ContentProviderObjects.ContentDatabase.class, db -> {
            try{
                new ArrayList<Class<? extends BaseProviderModel>>() {
                    {
                        add(ContentProviderObjects.NoteModel.class);
                        add(ContentProviderObjects.ContentProviderModel.class);
                    }
                }.forEach(aClass -> delete(aClass).executeUpdateDelete(db));
                ContentProviderObjects.ContentProviderModel contentProviderModel = new ContentProviderObjects.ContentProviderModel();
                contentProviderModel.notes = "Test";
                int id = ContentUtils.insert(mockContentResolver, TestContentProvider.ContentProviderModel.getCONTENT_URI(), contentProviderModel);
                assertEquals(TestContentProvider.ContentProviderModel.getCONTENT_URI().toString() + "/" + contentProviderModel.id, String.valueOf(id));
                assertTrue(contentProviderModel.exists(db));

                contentProviderModel.notes = "NewTest";
                int update = ContentUtils.update(mockContentResolver, TestContentProvider.ContentProviderModel.getCONTENT_URI(), contentProviderModel);
                assertEquals(update, 1);
                assertTrue(contentProviderModel.exists(db));
                contentProviderModel = contentProviderModel.load(db);
                assert contentProviderModel != null;
                assertEquals("NewTest", contentProviderModel.notes);

                ContentProviderObjects.NoteModel noteModel = new ContentProviderObjects.NoteModel();
                noteModel.note = "Test";
                noteModel.contentProviderModel = contentProviderModel;
                id = ContentUtils.insert(mockContentResolver, TestContentProvider.ContentProviderModel.getCONTENT_URI(), noteModel);
                assertEquals(TestContentProvider.NoteModel.getCONTENT_URI().toString() + "/" + noteModel.id, String.valueOf(id));
                assertTrue(noteModel.exists(db));

                assertTrue(ContentUtils.delete(mockContentResolver, TestContentProvider.NoteModel.getCONTENT_URI(), noteModel) > 0);
                assertFalse(noteModel.exists(db));

                assertTrue(ContentUtils.delete(mockContentResolver, TestContentProvider.ContentProviderModel.getCONTENT_URI(), contentProviderModel) > 0);
                assertFalse(contentProviderModel.exists(db));

                new ArrayList<Class<? extends BaseProviderModel>>() {
                    {
                        add(ContentProviderObjects.NoteModel.class);
                        add(ContentProviderObjects.ContentProviderModel.class);
                    }
                }.forEach(aClass -> delete(aClass).executeUpdateDelete(db));
            }catch (DataAbilityRemoteException e){
                e.printStackTrace();
            }
            return null;
        });
    }

    @Test
    public void testContentProviderNative() {
        FlowManager.database(ContentProviderObjects.ContentDatabase.class, db -> {
            try {
                new ArrayList<Class<? extends BaseProviderModel>>() {
                    {
                        add(ContentProviderObjects.NoteModel.class);
                        add(ContentProviderObjects.ContentProviderModel.class);
                    }
                }.forEach(aClass -> delete(aClass).executeUpdateDelete(db));
                ContentProviderObjects.ContentProviderModel contentProviderModel = new ContentProviderObjects.ContentProviderModel();
                contentProviderModel.notes = "Test";
                contentProviderModel.insert(db);
                assertTrue(contentProviderModel.exists(db));

                contentProviderModel.notes = "NewTest";
                contentProviderModel.update(db);
                contentProviderModel = contentProviderModel.load(db);
                assert contentProviderModel != null;
                assertEquals("NewTest", contentProviderModel.notes);

                ContentProviderObjects.NoteModel noteModel = new ContentProviderObjects.NoteModel();
                noteModel.note = "Test";
                noteModel.contentProviderModel = contentProviderModel;
                noteModel.insert(db);

                noteModel.note = "NewTest";
                noteModel.update(db);
                noteModel = noteModel.load(db);
                assert noteModel != null;
                assertEquals("NewTest", noteModel.note);

                assertTrue(noteModel.exists(db));

                noteModel.delete(db);
                assertFalse(noteModel.exists(db));

                contentProviderModel.delete(db);
                assertFalse(contentProviderModel.exists(db));

                new ArrayList<Class<? extends BaseProviderModel>>() {
                    {
                        add(ContentProviderObjects.NoteModel.class);
                        add(ContentProviderObjects.ContentProviderModel.class);
                    }
                }.forEach(aClass -> delete(aClass).executeUpdateDelete(db));
            }catch (Exception e){
                e.printStackTrace();
            }
            return null;
        });
    }

    @Test
    public void testSyncableModel() {
        FlowManager.database(ContentProviderObjects.ContentDatabase.class, db -> {
            try {
                delete(ContentProviderObjects.TestSyncableModel.class).execute(db);
                ContentProviderObjects.TestSyncableModel testSyncableModel=  new ContentProviderObjects.TestSyncableModel();
                testSyncableModel.name="Name";
                testSyncableModel.save(db);

                assertTrue(testSyncableModel.exists(db));

                testSyncableModel.name = "TestName";
                testSyncableModel.update(db);
                assertEquals(testSyncableModel.name, "TestName");

                testSyncableModel =SQLite.select().from(ContentProviderObjects.TestSyncableModel.class).where().querySingle(db);

                assert testSyncableModel != null;
                ContentProviderObjects.TestSyncableModel fromContentProvider = new ContentProviderObjects.TestSyncableModel();
                fromContentProvider.id = testSyncableModel.id;
                fromContentProvider = fromContentProvider.load(db);

                assert fromContentProvider != null;
                assertEquals(fromContentProvider.name, testSyncableModel.name);
                assertEquals(fromContentProvider.id, testSyncableModel.id);

                testSyncableModel.delete(db);
                assertFalse(testSyncableModel.exists(db));

                delete(ContentProviderObjects.TestSyncableModel.class).executeUpdateDelete(db);
            }catch (Exception e){
                e.printStackTrace();
            }
            return null;
        });
    }
}
